package com.example.selfservicestation.mob

import com.example.selfservicestation.util.Logger
import kotlin.experimental.xor

/**
 * 扫码数据解析器
 */
class ScanParser {

    /**
     * 解析扫码数据
     */
    fun parse(index: Int, data: ByteArray) : ScanData? {
        var result: ScanData? = null
        try {
            result = parseByNew(index, data)
        } catch (e: Exception) {
            Logger.e("ScanParserNew", "解析出错", e)
        }
        if (result == null) {
            try {
                result = parseByOld(index, data)
            } catch (e: Exception) {
                Logger.e("ScanParserOld", "解析出错", e)
            }
        }
        return result
    }

    companion object {

        private const val x00 = 0x00.toByte()
        private const val x01 = 0x01.toByte()
        private const val x02 = 0x02.toByte()
        private const val x03 = 0x03.toByte()
        private const val x0A = 0x0A.toByte()
        private const val x0D = 0x0D.toByte()
        private const val x55 = 0x55.toByte()
        private const val xAA = 0xAA.toByte()
        private const val xFF = 0xFF.toByte()

        private val cache = HashMap<Any, ScanParser>()

        fun getInstance(scannerId: Any) : ScanParser {
            return cache[scannerId]
                ?: ScanParser().also {
                    cache[scannerId] = it
                }
        }

    }

    private var newProtocol = false             // 是否是新的扫码头协议
    private var dataLast: ByteArray? = null     // 断包解析：上一帧数据
    private var error: Int = 0                  // 连续解析错误次数

    /**
     * 使用新协议解析
     */
    private fun parseByNew(index: Int, data: ByteArray) : ScanData? {
        if (!newProtocol) {
            return newToData(index,data)?.also {
                Logger.i("ScanParser", "扫码头协议进化")
                error = 0
                newProtocol = true
            }
        }
        dataLast?.let {
            newToData(index,it + data)?.let { scanData ->
                error = 0
                dataLast = null
                return scanData
            }
        }
        newToData(index,data)?.let {
            return it
        }
        if (dataLast != null) {
            error++
        }
        if (error > 3) {
            // 组包失败超过3次时，认为扫码头协议已被更换
            Logger.i("ScanParser", "扫码头协议退化：error = $error")
            error = 0
            newProtocol = false
            return null
        }
        dataLast = data
        return BrokenScanData(data.toHexString(true))
    }


    private fun newToData(index: Int,data: ByteArray) : ScanData? {
        // x01: 二维码 x02: IC卡 x03: ID卡
        if (data.size < 5 || data[0] != x02 || (data[1] != x01 && data[1] != x02 && data[1] != x03)) {
            return null
        }
        val length = data.to62Num(2, 4)
        if (data.size != 5 + length) {
            return null
        }
        if (xFF xor data.xor(4, 4 + length) != data[data.size - 1]) {
            return null
        }
        return ScanData(index,data[1] == x02 || data[1] == x03, String(data, 4, length))
    }


    /**
     * 使用老协议解析
     */
    private fun parseByOld(index: Int, data: ByteArray) : ScanData {
        if (data.size > 7 && data[0] == x55 && data[1] == xAA && data[3] == x00) {
            // 有些扫码头扫二维码和IC的输出内容一样，只是最后多了两个 0x0A 0x0D 字节
            if (data.xor(0, data.size - 3) == data[data.size - 3] && data[data.size - 2] == x0A && data[data.size - 1] == x0D) {
                val length = data.size - 9
                if (length.toByte() == data[4]) {
                    val content = String(data, 6, length)
                    return ScanData(
                        index,
                        isCard(content),
                        content
                    )
                }
            }
            // 有些扫码头扫二维码和IC的输出内容一样，只是最后多了一个 0x0D 字节
            if (data.xor(0, data.size - 2) == data[data.size - 2] && data[data.size - 1] == x0D) {
                val length = data.size - 8
                if (length.toByte() == data[4]) {
                    val content = String(data, 6, length)
                    return ScanData(
                        index,
                        isCard(content),
                        content
                    )
                }
            }
            // IC 卡 协议解析
            if (data.xor(0, data.size - 1) == data[data.size - 1]) {
                val length = data.size - 7
                if (length.toByte() == data[4]) {
                    val content = String(data, 6, length)
                    return ScanData(
                        index,
                        isCard(content),
                        content
                    )
                }
            }
        }
        // 有些扫码头扫二维码是原样输出内容
        val content = String(data)
        return ScanData(
            index,
            isCard(content),
            content
        )
    }

    private fun isCard(content: String) : Boolean {
        return content.matches(Regex("[0-9]+")) && content.length == 10
    }

}


open class ScanData(
    val index: Int,
    val isCard: Boolean,
    val data: String

) {

    override fun toString(): String {
        return "ScanData(isCard=$isCard, data='$data')"
    }

}

/**
 * 扫码头断包数据
 */
class BrokenScanData(data: String): ScanData(-1,false, data) {

    override fun toString(): String {
        return "BrokenScanData(data='$data')"
    }

}